package com.myersinfosys.protrack.vfs;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSelector;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.Selectors;
import org.apache.commons.vfs.impl.DefaultFileMonitor;


/** FileSessionConnector - Public class handling the operations between source and destination file sessions.
*
* @author E.Morris
* @version 4/15/2011
*/
public class FileSessionConnector {
	private FileSessionManager manager = null;
	private static Log log = LogFactory.getLog(FileSessionConnector.class);
	private FileSession source = null;
	private FileSession destination = null;
	private DefaultFileMonitor destinationMonitor=null;

	public FileSessionConnector(FileSessionManager manager, FileSession sourceSession, FileSession destinationSession) {
		this.manager = manager;
		this.source = sourceSession;
		this.destination = destinationSession;
	}
	
	public FileSessionConnector(FileSessionManager manager, String sourceSessionName, String destinationSessionName) throws FileSystemException {
		
		this.manager = manager;
		
		if(sourceSessionName!=null) {
			source = new FileSession(this.manager, sourceSessionName);
			if(source!=null) {
				
			} else {
				System.out.println("could not log in to source");
			}
		}
		
		if(destinationSessionName!=null) {
			destination = new FileSession(this.manager, destinationSessionName);
			if(destination!=null) {
			
			} else {
				System.out.println("could not log in to destination");
			}
		}
	}
	
	public void closeFileSessionConnector() {
		if(destinationMonitor != null) {
			destinationMonitor.stop();
		}
		if(source != null) {
			source.closeFileSession();
		}
		if(destination != null) {
			destination.closeFileSession();
		}
	}

	public FileSession getSource() {
		return this.source;
	}
	
	public FileSession getDestination() {
		return this.destination;
	}	
	
	public void startMonitor(FileObject sessionFileObject) {
		if(destinationMonitor==null) {
			destinationMonitor = new DefaultFileMonitor(new FileSessionListener(log));
		}	
		
		//destinationMonitor.setRecursive(true);
		destinationMonitor.addFile(sessionFileObject);
		destinationMonitor.setDelay(100);
		//destinationMonitor.setChecksPerRun(10);
		destinationMonitor.start();
		//destinationMonitor.run();		
	}
	
	public void stopMonitor(FileObject sessionFileObject) {
		if(destinationMonitor != null) {
			destinationMonitor.removeFile(sessionFileObject);
		}
	}
	
	public List<String> listFilesFromSource(final String patternMatch, final boolean includeChildren) {
		List<String> slist = new ArrayList<String>();
		List<FileObject> flist = listFiles(this.source, patternMatch, includeChildren);
		
		for(FileObject f : flist) {
			slist.add(f.getName().getPath());
		}
		
		return slist;
	}
	
	public List<String> listFilesFromDestination(final String patternMatch, final boolean includeChildren) {
		List<String> slist = new ArrayList<String>();
		List<FileObject> flist = listFiles(this.destination, patternMatch, includeChildren);
		
		for(FileObject f : flist) {
			slist.add(f.getName().getPath());
		}
		
		return slist;
	}	
	
	public List<FileObject> listFiles(final FileSession session, final String patternMatch, final boolean includeChildren) {
		List<FileObject> flist = new ArrayList<FileObject>();
		FileObject src = session.getParent();
		
		if(src!=null) {
			try {
				FileSessionSelector selector = new FileSessionSelector(patternMatch);
				
				src.findFiles(selector, false, flist);
				
			} catch (FileSystemException e) {
				e.printStackTrace();
			}
		}
		
		return flist;
	}
	
	
	public boolean copyFiles(final String patternMatch, final boolean includeChildren, final boolean overwrite) {
		boolean success = false;
		
		FileObject src = this.source.getParent();
		FileObject dest = this.destination.getParent();
		
		if(src!=null && dest!=null) {
			try {
				FileSessionSelector selector = new FileSessionSelector(patternMatch);
				
				// process matching files one at a time
				List<FileObject> flist = new ArrayList<FileObject>();
				src.findFiles(selector, false, flist);
				
				for(FileObject f : flist) {
					FileObject destFile = dest.resolveFile(f.getName().getBaseName());
					FileSelector sel = (includeChildren) ? Selectors.SELECT_ALL : Selectors.SELECT_SELF;
					if(overwrite || (!overwrite && !destFile.exists())) {
						destFile.copyFrom(f, sel);
					} else {
						log.warn(destFile.getName().getPath() + " Already Exists - not copied");
					}
				}
				success = true;
			} catch (FileSystemException e) {
				e.printStackTrace();
			}
		}
		
		return success;
	}
	
	public boolean moveFiles(final String patternMatch, final boolean includeChildren, final boolean overwrite) {
		boolean success = false;
		
		if(copyFiles(patternMatch, includeChildren, overwrite)) {
			success = removeFilesFromSource(patternMatch);
		}
		
		return success;
	}
	
	public boolean removeFilesFromSource(final String patternMatch) {
		return removeFiles(this.source, patternMatch);
	}
	
	public boolean removeFilesFromDestination(final String patternMatch) {
		return removeFiles(this.destination, patternMatch);
	}	
	
	private boolean removeFiles(FileSession session, final String patternMatch) {
		boolean success = false;
		
		FileObject src = session.getParent();
		
		if(src!=null) {
			try {
				FileSessionSelector selector = new FileSessionSelector(patternMatch);
				
				// process matching files one at a time
				List<FileObject> flist = new ArrayList<FileObject>();
				src.findFiles(selector, false, flist);
				
				for(FileObject f : flist) {
					FileObject srcFile = src.resolveFile(f.getName().getBaseName());
					FileSelector sel = Selectors.SELECT_ALL;
					srcFile.delete(sel);
				}
				success = true;
			} catch (FileSystemException e) {
				e.printStackTrace();
			}
		}
		
		return success;
	}
	
}
